import base64
import pickle
import sys
import os
from django.conf import settings
from django.core.mail import send_mail

from areas.models import Area
from goods.models import SKU
from utils.access_token import decode_access_token

sys.path.insert(0, os.path.dirname(settings.BASE_DIR))

import json
from django.contrib.auth import login, logout
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponse, HttpResponseForbidden
from django.http import HttpResponseRedirect
from django.http import JsonResponse
from django.shortcuts import render, redirect
import re
from utils.myemail import generate_verify_email_url, decode_email_token
from django.utils.decorators import method_decorator
from django.views import View
from django_redis import get_redis_connection
from users.models import User, Address
from apps.users.utils import MyModelBackend


class RegisterView(View):
    def get(self, request):
        return render(request, 'register_vue.html', {})

    def post(self, request):
        # 接受数据
        data = request.POST
        user_name = data.get('user_name')
        pwd = data.get('pwd')
        cpwd = data.get('cpwd')
        phone = data.get('phone')
        msg_code = data.get('msg_code')
        allow = data.get('allow')

        # 校验数据
        if not all([user_name, pwd, cpwd, phone]):
            return HttpResponseForbidden('参数不全')

        if not re.match('^[a-zA-Z0-9_-]{5,20}$', user_name):
            return HttpResponseForbidden('用户名格式错误')

        if not re.match('^[0-9A-Za-z]{8,20}$', pwd):
            return HttpResponseForbidden('密码格式错误')

        if pwd != cpwd:
            return HttpResponseForbidden('两次输入密码不一致')

        if not re.match('^1[345789]\d{9}$', phone):
            return HttpResponseForbidden('手机号格式错误')

        redis_client = get_redis_connection('verify_code')
        redis_code = redis_client.get(phone)

        if redis_code:
            redis_code = redis_code.decode()

        if redis_code != msg_code:
            return HttpResponseForbidden('短信验证码错误')

        if allow != 'on':
            return HttpResponseForbidden('请勾选用户协议')

        # 处理业务
        try:
            User.objects.create_user(username=user_name, password=pwd, mobile=phone)
            redis_client.delete(phone)
        except Exception:
            return HttpResponseForbidden('创建用户失败')

        # 响应
        return HttpResponseRedirect('/login')


class CheckUsernameView(View):
    def get(self, request, username):
        count = User.objects.filter(username=username).count()

        res = {
            'code': 0,
            'errmsg': 'OK',
            'count': count
        }

        return JsonResponse(res)


class CheckPhoneView(View):
    def get(self, request, phone):
        count = User.objects.filter(mobile=phone).count()

        res = {
            'code': 0,
            'errmsg': 'OK',
            'count': count
        }

        return JsonResponse(res)


class LoginView(View):
    def get(self, request):

        return render(request, 'login.html')

    def post(self, request):

        # 1 接受数据
        username = request.POST.get('username')
        password = request.POST.get('pwd')
        remembered = request.POST.get('remembered')

        # 2 校验数据
        if not all([username, password]):
            return HttpResponseForbidden('参数不全')

        # 3 处理业务
        # try:
        #     user = User.objects.get(username=username)
        # except Exception as e:
        #     print(e)
        #     return HttpResponseForbidden('用户不存在')


        from django.contrib.auth import authenticate

        user = authenticate(request, username=username, password=password)

        # print(user)

        if not user:
            return HttpResponseForbidden('密码错误')

        login(request, user)

        next = request.GET.get('next')
        if not next:
            next = '/'

        response = redirect(next)

        if remembered != 'on':
            request.session.set_expiry(0)
            response.set_cookie('username', user.username)

        else:
            request.session.set_expiry(None)
            response.set_cookie('username', user.username, expires=3600 * 24 * 14)

        # 获取cookie中的购物车信息
        carts = request.COOKIES.get('carts')
        if carts:
            redis_client = get_redis_connection('carts')

            cart_dict = pickle.loads(base64.b64decode(carts))

            for sku_id, info in cart_dict.items():
                redis_client.sadd('selected_%s' % user.id, sku_id)
                count = redis_client.hget('cart_%s' % user.id, sku_id)
                if count:
                    redis_client.hset('cart_%s' % user.id, sku_id, int(count) + int(info['count']))
                else:
                    redis_client.hset('cart_%s' % user.id, sku_id, int(info['count']))

        response.delete_cookie('carts')
        return response


class LogoutView(View):
    def get(self, request):
        logout(request)

        response = redirect('/')
        response.delete_cookie('username')

        return response


class UserCenterInfoView(LoginRequiredMixin, View):
    def get(self, request):
        user = request.user

        redis_client = get_redis_connection('history')
        histories = redis_client.lrange('history_%s' % user.id, 0, 5)
        history_skus = []
        for history in histories:
            history_skus.append(SKU.objects.get(id=history))
        context = {
            'username': user.username,
            'mobile': user.mobile,
            'email': user.email,
            'email_active': user.email_active,
            'histories': history_skus
        }

        return render(request, 'user_center_info.html', context=context)


class EmailView(LoginRequiredMixin, View):
    # def get(self,request):
    #     from django.core.mail import send_mail
    #     send_mail('meiduo_mall', 'hello', '910165585@qq.com', ['540082271@qq.com'])
    #     return HttpResponse('haha')

    def put(self, request):

        # receive data
        json_dict = json.loads(request.body.decode())
        email = json_dict.get('email')
        # email = 'kv_summer@126.com'

        # check data
        if not email:
            return HttpResponseForbidden('argument lost')

        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return HttpResponseForbidden('email error')

        # data processing
        try:
            request.user.email = email
            request.user.save()

        except Exception as e:
            return JsonResponse({"code": 9999, "errmsg": "failed to add email"})

        verify_email_url = generate_verify_email_url(request.user.id)
        # print(verify_email_url)

        from celery_task.main import send_verify_email
        send_verify_email.delay('email verify', email, verify_email_url)

        return JsonResponse({"code": 0, "errmsg": "OK"})


class EmailActiveView(View):
    def get(self, request):
        token = request.GET.get('token')

        user_id = decode_email_token(token)

        if not user_id:
            return HttpResponseForbidden('token expired')

        try:
            user = User.objects.get(id=user_id)

        except Exception:
            return HttpResponse('user is not existed')

        user.email_active = True
        login(request, user)
        request.session.set_expiry(None)
        response = redirect('/info')
        response.set_cookie('username', user.username, expires=60 * 5)
        response.set_cookie('email_active', user.email_active, expires=60 * 5)

        return response


class AddressesView(LoginRequiredMixin, View):
    def get(self, request):
        user = request.user

        addrs = Address.objects.filter(user=user, is_deleted=False)

        addr_list = []
        for addr in addrs:
            addr_data = {
                "id": addr.id,
                "title": addr.title,
                "receiver": addr.receiver,
                "province": addr.province.name,
                "province_id": addr.province.id,
                "city": addr.city.name,
                "city_id": addr.city.id,
                "district": addr.district.name,
                "district_id": addr.district.id,
                "place": addr.place,
                "mobile": addr.mobile,
                "tel": addr.tel,
                "email": addr.email
            }
            addr_list.append(addr_data)

        context = {
            "addresses": json.dumps(addr_list),
            "default_address_id": user.default_address_id
        }

        return render(request, 'user_center_site.html', context=context)


class AddressesCreateView(LoginRequiredMixin, View):
    def post(self, request):

        data = json.loads(request.body.decode())
        title = data.get('title')
        receiver = data.get('receiver')
        province_id = data.get('province_id')
        city_id = data.get('city_id')
        district_id = data.get('district_id')
        place = data.get('place')
        mobile = data.get('mobile')
        tel = data.get('tel')
        email = data.get('email')

        if not all([title, receiver, province_id, city_id, district_id, place, mobile]):
            return JsonResponse({'code': 9999, 'errmsg': 'arguments lost'})

        try:
            province = Area.objects.get(id=province_id)
            city = Area.objects.get(id=city_id)
            district = Area.objects.get(id=district_id)
        except:
            return JsonResponse({"code": 9999, "errmsg": "地址数据错误"})

        if not re.match('^1[345789]\d{9}$', mobile):
            return JsonResponse({"code": 9999, "errmsg": "手机格式错误"})

        if email and (not re.match('^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email)):
            return JsonResponse({"code": 9999, "errmsg": "邮箱格式错误"})

        user = request.user

        addr = Address.objects.create(
            user=user,
            title=title,
            receiver=receiver,
            province=province,
            city=city,
            district=district,
            place=place,
            mobile=mobile,
            tel=tel,
            email=email
        )

        res = {
            'code': 0,
            'errmsg': 'OK',
            'address': {
                "id": addr.id,
                "title": addr.title,
                "receiver": addr.receiver,
                "province": addr.province.name,
                "province_id": addr.province.id,
                "city": addr.city.name,
                "city_id": addr.city.id,
                "district": addr.district.name,
                "district_id": addr.district.id,
                "place": addr.place,
                "mobile": addr.mobile,
                "tel": addr.tel,
                "email": addr.email
            }
        }
        return JsonResponse(res)


# modify or delete address information
class AddressesUpdateView(LoginRequiredMixin, View):
    def put(self, request, address_id):

        data = json.loads(request.body.decode())
        receiver = data.get('receiver')
        province_id = data.get('province_id')
        city_id = data.get('city_id')
        district_id = data.get('district_id')
        place = data.get('place')
        mobile = data.get('mobile')
        tel = data.get('tel')
        email = data.get('email')

        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return JsonResponse({'code': 9999, 'errmsg': 'arguments lost'})

        try:
            province = Area.objects.get(id=province_id)
            city = Area.objects.get(id=city_id)
            district = Area.objects.get(id=district_id)
        except:
            return JsonResponse({"code": 9999, "errmsg": "地址数据错误"})

        if not re.match('^1[345789]\d{9}$', mobile):
            return JsonResponse({"code": 9999, "errmsg": "手机格式错误"})

        if email and (not re.match('^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email)):
            return JsonResponse({"code": 9999, "errmsg": "邮箱格式错误"})

        user = request.user

        try:
            addr = Address.objects.get(id=address_id)
        except:
            return JsonResponse({'code': 9999, 'errmsg': 'error title'})

        # addr = Address.objects.create(
        #     user=user,
        #     title=title,
        #     receiver=receiver,
        #     province=province,
        #     city=city,
        #     district=district,
        #     place=place,
        #     mobile=mobile,
        #     tel=tel,
        #     email=email
        # )
        addr.user = user
        addr.receiver = receiver
        addr.province = province
        addr.city = city
        addr.district = district
        addr.place = place
        addr.mobile = mobile
        addr.tel = tel
        addr.email = email

        addr.save()

        res = {
            'code': 0,
            'errmsg': 'OK',
            'address': {
                "id": addr.id,
                "title": addr.title,
                "receiver": addr.receiver,
                "province": addr.province.name,
                "city": addr.city.name,
                "district": addr.district.name,
                "place": addr.place,
                "mobile": addr.mobile,
                "tel": addr.tel,
                "email": addr.email
            }
        }
        return JsonResponse(res)

    def delete(self, request, address_id):

        try:
            addr = Address.objects.get(id=address_id)

        except:
            return JsonResponse({'code': 9999, 'errmsg': 'address not found'})

        addr.is_deleted = True
        addr.save()

        res = {
            'code': 0,
            'errmsg': 'OK'
        }
        return JsonResponse(res)


# set default address
class AddressesDefaultView(LoginRequiredMixin, View):
    def put(self, request, address_id):

        try:
            addr = Address.objects.get(id=address_id)

        except Exception as e:
            res = {
                'code': 9999,
                'errmsg': 'error address ID'
            }
            return JsonResponse(res)

        user = addr.user
        user.default_address = addr
        user.save()

        res = {
            'code': 0,
            'errmsg': 'OK'
        }
        return JsonResponse(res)


# update title
class AddressesTitleView(LoginRequiredMixin, View):
    def put(self, request, address_id):
        data = json.loads(request.body.decode())
        title = data.get('title')

        if not title:
            return JsonResponse({'code': 9999, 'errmsg': 'arguments lost'})

        try:
            addr = Address.objects.get(id=address_id)
        except Exception as e:
            return JsonResponse({'code': 9999, 'errmsg': 'error ID'})

        addr.title = title
        addr.save()

        res = {
            'code': 0,
            'errmsg': 'OK'
        }
        return JsonResponse(res)


# modify password
class PasswordChangeView(LoginRequiredMixin, View):
    def get(self, request):
        return render(request, 'user_center_pass.html')

    def post(self, request):
        opwd = request.POST.get('old_pwd')
        npwd = request.POST.get('new_pwd')
        cpwd = request.POST.get('new_cpwd')

        if not all([opwd, npwd, cpwd]):
            return HttpResponseForbidden('arguments lost')

        user = request.user

        if not user.check_password(raw_password=opwd):
            return HttpResponseForbidden('old password is wrong')

        if not npwd == cpwd:
            return HttpResponseForbidden('wrong')

        user.set_password(raw_password=npwd)
        user.save()

        logout(request)
        response = redirect('/login')
        response.delete_cookie('username')

        return response


class FindPasswordView(View):
    def get(self, request):
        return render(request, 'find_password.html')


class SetNewPasswordView(View):
    def post(self, request, user_id):

        json_data = request.body.decode()
        try:
            json_dict = json.loads(json_data)
        except:
            return HttpResponseForbidden('json lost')

        password = json_dict.get('password')
        password2 = json_dict.get('password2')
        token = json_dict.get('access_token')

        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return HttpResponseForbidden('illegal password')

        if password != password2:
            return HttpResponseForbidden('two password different')

        try:
            user = User.objects.get(id=user_id)
        except:
            return HttpResponseForbidden('user is not existed')

        if not token:
            return HttpResponseForbidden('token is expired')

        username = decode_access_token(token)

        if username != user.username:
            return HttpResponseForbidden('error token')

        user.set_password(raw_password=password)
        user.save()

        res = {
            'code': 0,
            'errmsg': 'OK'
        }

        return JsonResponse(res)